/*
 *  RootSetUpdate.java        14-nov-2009
 *   
 * Copyright (c) 2009 mentalsmash.org
 *  
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 * 
 *  http://www.apache.org/licenses/LICENSE-2.0
 * 
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 * 
 *  The use of the Apache License does not indicate that this project is
 *  affiliated with the Apache Software Foundation.
 */
package org.mentalsmash.tazio.transactions.model;

import java.io.Serializable;

import org.mentalsmash.tazio.transactions.model.identifiers.OID;

import com.google.common.base.Preconditions;

/**
 * 
 * @author Andrea Reale
 * @version 0.0.1
 * 
 */
public class RootSetUpdate extends SetUpdate {

    private static final long serialVersionUID = -6245735790039384312L;

    public RootSetUpdate(final long originalVersion, final boolean removal) {
	super(RootSet.ROOT_SET_OID, originalVersion, removal);
    }

    /**
     * The value of a RootSetUpdate operations is managed differntly from a
     * standard {@link SetUpdate} value.
     * <p>
     * In fact, while in normal <tt>SetUpdate</tt>s a value may be a primitive
     * type or an OID both in the case of addition and removal, in a
     * <tt>RootSetUpdate</tt> it depends on the operation:
     * <ul>
     * <li>1. <strong>Addition</strong> The value has to be an instance of
     * {@link TransactionalObject}, representing the actual object that is going
     * to be added to the RootSet. That object should not already be in the
     * RootSet, even tough no such a check is performed in this method</li>
     * <li>1. <strong>Removal</strong> The value has to be an instance of
     * {@link OID}, pointing to an object that aready is in the RootSet. (No
     * such a check is performed in this moment, by this method)</li>
     * </ul>
     * </p>
     */
    public void setValue(final Serializable value) {
	Preconditions.checkNotNull(value);
	if (isRemoval()) {
	    Preconditions.checkArgument(value instanceof OID);
	} else {
	    Preconditions.checkArgument(value instanceof TransactionalObject);
	}
	super.setValue(value);
    }

    @Override
    public void commitOperation(final RootSet rs) {
	Preconditions
		.checkState(getValue() != null,
			"Value for a RootSetUpdate cannot be null. Call setValue() first");
	if (this.isRemoval()) {
	    removeFromRootSet(rs);
	} else {
	    addToRootSet(rs);
	}
    }

    private void addToRootSet(final RootSet rs) {
	if (rs.containsObject(((TransactionalObject) getValue())
		.getObjectIdentifier())) {
	    log.warn(
		    "WARNING: the RootSet did already contain an object having OID {}:"
			    + " adding nothing",
		    ((TransactionalObject) getValue()).getObjectIdentifier());
	    return;
	}
	rs.doAddObject((TransactionalObject) this.getValue());

    }

    private void removeFromRootSet(final RootSet rs) {
	if (!rs.containsObject((OID) getValue())) {
	    log.warn("WARNING: trying to remove from the "
		    + "RootSet object {} that wasn't in the root set", this
		    .getValue());
	    return;
	}
	rs.doRemoveObject((OID) this.getValue());
    }

}
